import React, { useState, useRef } from 'react';
import { Table } from 'antd';
import { useDrop, useDrag } from 'react-dnd';
import { Resizable } from 'react-resizable';
import type { ColumnsType } from 'antd/es/table';
import './index.less';

interface Command {
    id: string;
    name: string;
    description: string;
    type: string;
}

interface HandleProps {
    handleAxis: string;
    [key: string]: any;
}

interface DataType {
    key: string;
    [key: string]: any;
}

interface TableViewProps {
    data: DataType[];
    columns: ColumnsType<DataType>;
    onDataChange?: (data: DataType[]) => void;
}

interface ResizableTitleProps {
    onResize: (e: React.SyntheticEvent, { size }: { size: { width: number; height: number } }) => void;
    width?: number;
    lastResized?: boolean;
}

interface DraggableRowProps {
    index: number;
    moveRow: (dragIndex: number, hoverIndex: number) => void;
    addRow: (index: number, data: DataType) => void;
    className?: string;
    style?: React.CSSProperties;
    children: React.ReactNode;
}

function DraggableRow({ index, moveRow, addRow, className, style, children }: DraggableRowProps) {
    const ref = useRef<HTMLTableCellElement>(null);
    const [{ isDragging }, drag, preview] = useDrag({
        type: 'ROW',
        item: { index, type: 'ROW' },
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
        }),
    });

    const [{ isOver, dropPosition }, drop] = useDrop({
        accept: ['ROW', 'COMMAND'],
        // hover: (item: { index: number, type: string }) => {
        //     if (!ref.current) {
        //         return;
        //     }
        //     if (item.type === 'ROW') {
        //         const dragIndex = item.index;
        //         const hoverIndex = index;

        //         if (dragIndex === hoverIndex) {
        //             return;
        //         }

        //         moveRow(dragIndex, hoverIndex);
        //         item.index = hoverIndex;
        //     }
        // },
        collect: (monitor) => {
            if (!ref.current) {
                return {
                    isOver: false,
                    dropPosition: null,
                };
            }

            const clientOffset = monitor.getClientOffset();
            if (!clientOffset) {
                return {
                    isOver: false,
                    dropPosition: null,
                };
            }

            const rect = ref.current.getBoundingClientRect();
            const hoverMiddleY = (rect.bottom - rect.top) / 2;
            const hoverClientY = clientOffset.y - rect.top;

            return {
                isOver: monitor.isOver(),
                dropPosition: hoverClientY < hoverMiddleY ? 'top' : 'bottom',
            };
        },
        drop: (item: { index: number, type: string, command: Command }) => {
            if (item.type === 'COMMAND') {
                // 新增
                addRow(dropPosition === 'top' ? index : index + 1, {
                    key: Date.now().toString(),
                    command: item.command.name,
                    target: '',
                    value: '',
                });
            } else if (item.type === 'ROW') {
                const dragIndex = item.index;
                const hoverIndex = index;
                if (dragIndex === hoverIndex) {
                    return;
                }
                moveRow(dragIndex, hoverIndex);
                item.index = hoverIndex;
            }
        }
    });

    return (
        <tr
            ref={(node) => {
                preview(node);
                drop(node);
            }}
            className={`${className} ${isDragging ? 'dragging' : ''} ${isOver ? `drop-${dropPosition}` : ''}`}
            style={{
                ...style,
                opacity: isDragging ? 0.5 : 1,
            }}
        >
            {children}
            <td ref={(node) => {
                ref.current = node;
                drag(drop(ref));
            }} className='move-btn' style={{ cursor: 'move' }}>
                移动
            </td>
        </tr>
    );
};

const DragHandle = React.forwardRef<HTMLDivElement, HandleProps>((props, ref) => {
    const { handleAxis, ...restProps } = props;
    return <div ref={ref} className={`th-resizable-handle handle-${handleAxis}`} {...restProps} />;
});

function ResizableTitle({ onResize, width, lastResized, ...restProps }: ResizableTitleProps) {
    if (!width) {
        return <th {...restProps} />;
    }

    return (
        <Resizable
            width={width || 0}
            handle={<DragHandle />}
            onResize={onResize}
            draggableOpts={{ enableUserSelectHack: false }}
            axis='x'
        >
            <th style={{ width }} {...restProps} />
        </Resizable>
    );
};

export default function TableView({ data, columns, onDataChange }: TableViewProps) {
    const [dataSource, setDataSource] = useState<DataType[]>(data);
    const [resizedColumns, setResizedColumns] = useState<ColumnsType<DataType>>(columns);

    const moveRow = (dragIndex: number, hoverIndex: number) => {
        const newData = [...dataSource];
        const [removed] = newData.splice(dragIndex, 1);
        newData.splice(hoverIndex, 0, removed);
        setDataSource(newData);
        onDataChange?.(newData);
    };

    const addRow = (index: number, data: DataType) => {
        const newData = [...dataSource];
        newData.splice(index, 0, {
            ...data,
            key: Date.now().toString(),
        });
        setDataSource(newData);
    };


    const handleResize = (index: number) => (e: React.SyntheticEvent, { size }: { size: { width: number; height: number } }) => {
        setResizedColumns(prevColumns => {
            const nextColumns = [...prevColumns];
            nextColumns[index] = {
                ...nextColumns[index],
                width: Math.max(size.width, 100),
            };
            return nextColumns;
        });
    };

    const mergedColumns = resizedColumns.map((col, index) => ({
        ...col,
        onHeaderCell: () => ({
            width: col.width,
            onResize: handleResize(index),
        } as unknown as React.HTMLAttributes<HTMLTableCellElement>),
    })) as ColumnsType<DataType>;

    const components = {
        header: {
            row: (props: any) => {
                console.log('props', props);
                const { children, ...restProps } = props;
                return <tr {...restProps} >
                    {children}
                    <th>
                        移动
                    </th>
                </tr>;
            },
            cell: ResizableTitle,
        },
        body: {
            row: (props: any) => {
                console.log('props', props);
                const index = props['data-row-key'] ? dataSource.findIndex(item => item.key === props['data-row-key']) : -1;
                if (index === -1) return <tr {...props} />;
                return <DraggableRow index={index} addRow={addRow} moveRow={moveRow} {...props} />;
            },
            cell: (props: any) => {
                console.log('props', props);
                const { children, ...resetProps } = props;
                return <td {...resetProps} >{children}</td>;
            }
        },
    };

    return (
        <div>
            <Table
                components={components}
                columns={mergedColumns}
                dataSource={dataSource}
                pagination={false}
                rowKey="key"
            />
        </div>
    );
};

